package com.dhcc.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.dhcc.api.R;
import com.dhcc.entity.*;
import com.dhcc.service.*;
import com.dhcc.utils.AuthUtil;
import com.dhcc.utils.JsonUtils;
import com.dhcc.utils.ResourceTreeBuilder;
import com.dhcc.response.SysResourceListTree;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.annotation.Resource;
import com.fasterxml.jackson.core.type.TypeReference;
import org.springframework.web.bind.annotation.*;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * 系统服务控制层接口
 * @ProjectName Dhcc-Cloud
 * @PackageName com.dhcc.controller
 * @Title SystemController
 * @Date 2024/12/5 下午3:16
 * @Author LiuGuoting
 */
@RestController
@RequestMapping("/sys")
public class SystemController {
    @Resource
    private SysUserService sysUserService;
    @Resource
    private SysPositionService sysPositionService;
    @Resource
    private SysDeptService sysDeptService;
    @Resource
    private SysDeptPositionUserService sysDeptPositionUserService;
    @Resource
    private SysDeptPositionService sysDeptPositionService;
    @Resource
    private SysDeptPositionResourceService sysDeptPositionResourceService;
    @Resource
    private SysResourceService sysResourceService;
    @Resource
    private SysApiPermService sysApiPermService;
    @Resource
    private RedisService redisService;
    /**
     * 设置新的令牌的过期时间：60 分钟
     */
    private final long expireTime = 3600L;
    /**
     * 设置令牌过期时间的单位：秒
     */
    private final TimeUnit timeUnit = TimeUnit.SECONDS;

    /** 查询登录用户的用户信息
     * @return 用户信息
     */
    @GetMapping("/userInfo")
    public R<SysUser> userInfo() {
        return R.data(sysUserService.getById(AuthUtil.getUserId()));
    }

    /**
     * 获取当前登录用户的部门列表信息
     * @return R<List<SysDept> 部门列表信息
     */
    @GetMapping("/getSysLoginDept")
    public R<Set<SysDept>> getSysLoginDept(){
        // 定义一个List集合，用于存储当前登录用户的部门列表信息
        Set<SysDept> sysDepts = new HashSet<>();
        // 获取当前登录用户的部门岗位关联列表
        List<SysDeptPositionUser> idsByUserId = sysDeptPositionUserService.getIdsByUserId(AuthUtil.getUserId());
        for (SysDeptPositionUser sysDeptPositionUser : idsByUserId) {
            // 遍历获取到部门岗位的关联记录ID
            Long deptPositionId = sysDeptPositionUser.getDepartmentPosition();
            // 根据关联记录ID获取部门岗位的记录数据
            LambdaQueryWrapper<SysDeptPosition> sysDeptPositionLambdaQueryWrapper = new LambdaQueryWrapper<>();
            SysDeptPosition deptPosition = sysDeptPositionService.getOne(sysDeptPositionLambdaQueryWrapper.eq(SysDeptPosition::getId, deptPositionId));
            Long departmentId = deptPosition.getDepartmentId();
            // 根据部门ID获取部门的记录数据
            LambdaQueryWrapper<SysDept> sysDeptLambdaQueryWrapper = new LambdaQueryWrapper<>();
            sysDeptLambdaQueryWrapper.eq(SysDept::getId, departmentId);
            SysDept sysDept = sysDeptService.getOne(sysDeptLambdaQueryWrapper);
            sysDepts.add(sysDept);
        }
        return R.data(sysDepts);
    }

    /**
     * 获取当前登录用户的当前选择部门下的岗位列表信息
     * @param deptId 部门ID
     * @return R
     */
    @GetMapping("/getSysLoginPosition")
    public R<Set<SysPosition>> getSysLoginPosition(String deptId){
        // 定义一个List集合，用于存储当前登录用户的岗位列表信息
        Set<SysPosition> sysPositions = new HashSet<>();

        // 获取当前登录用户的部门岗位与用户关联列表
        List<SysDeptPositionUser> idsByUserId = sysDeptPositionUserService.getIdsByUserId(AuthUtil.getUserId());
        // 遍历获取到部门岗位与用户的关联记录ID
        for (SysDeptPositionUser sysDeptPositionUser : idsByUserId) {
            // 遍历获取到部门岗位与用户的关联记录ID
            Long deptPositionId = sysDeptPositionUser.getDepartmentPosition();
            // 根据部门岗位关联记录的ID和当前选择的部门ID获取部门岗位的记录数据
            LambdaQueryWrapper<SysDeptPosition> sysDeptPositionLambdaQueryWrapper = new LambdaQueryWrapper<>();
            sysDeptPositionLambdaQueryWrapper.eq(SysDeptPosition::getId, deptPositionId);
            sysDeptPositionLambdaQueryWrapper.eq(SysDeptPosition::getDepartmentId, deptId);
            SysDeptPosition deptPosition = sysDeptPositionService.getOne(sysDeptPositionLambdaQueryWrapper);
            // 判断部门岗位是否为空
            if (deptPosition != null) {
                // 获取部门岗位关联记录的岗位ID
                Long positionId = deptPosition.getPositionId();
                // 根据部门岗位的岗位ID获取岗位的详细信息
                LambdaQueryWrapper<SysPosition> sysDeptPositionUserLambdaQueryWrapper = new LambdaQueryWrapper<>();
                sysDeptPositionUserLambdaQueryWrapper.eq(SysPosition::getId, positionId);
                SysPosition sysPosition = sysPositionService.getOne(sysDeptPositionUserLambdaQueryWrapper);
                // 添加到岗位列表集合中
                sysPositions.add(sysPosition);
            }
        }
        // 返回岗位列表集合
        return R.data(sysPositions);
    }

    /**
     * 查询接口权限并缓存至Redis中
     * 提交部门及岗位选择，并获取当前登录用户所选择的部门下的某岗位的菜单列表数据
     * @param body
     * @return
     */
    @PostMapping("/deptAndPositionLogin")
    public R<List<SysResourceListTree>> deptAndPositionLogin(@RequestBody Map<String, String> body) throws JsonProcessingException {
        SysUser sysUser = sysUserService.getById(AuthUtil.getUserId());
        String userName = sysUser.getUserName();
        // 从body中获取deptId和positionId
        String deptId = body.get("deptId");
        String positionId = body.get("positionId");
        // 继续处理业务逻辑
        // 1.获取当前登录用户所选择的部门下的某岗位的接口权限列表
        Set<String> authApi = new HashSet<>();
        // 获取当前登录用户的部门岗位关联列表
        Set<Long> departmentPositions = new HashSet<>();
        // 获取当前用户登录的部门下岗位所拥有的部门岗位-资源（菜单）关联关系列表
        List<SysDeptPositionResource> sysDeptPositionResources = new ArrayList<>();
        // 获取当前登录用户所选择的部门下岗位所拥有的资源（菜单）列表
        Set<SysResource> sysResources = new HashSet<>();


        List<SysDeptPositionUser> sysDeptPositionUsers = sysDeptPositionUserService.getIdsByUserId(AuthUtil.getUserId());
        for (SysDeptPositionUser sysDeptPositionUser : sysDeptPositionUsers) {
            Long departmentPosition = sysDeptPositionUser.getDepartmentPosition();
            // 筛选出入参指定的部门id和岗位id的记录
            LambdaQueryWrapper<SysDeptPosition> sysDeptPositionLambdaQueryWrapper = new LambdaQueryWrapper<>();
            sysDeptPositionLambdaQueryWrapper.eq(SysDeptPosition::getId, departmentPosition);
            sysDeptPositionLambdaQueryWrapper.eq(SysDeptPosition::getDepartmentId, deptId);
            sysDeptPositionLambdaQueryWrapper.eq(SysDeptPosition::getPositionId, positionId);
            SysDeptPosition deptPosition = sysDeptPositionService.getOne(sysDeptPositionLambdaQueryWrapper);
            // 判断选择的部门岗位关联记录是否为空
            if (deptPosition != null) {
                // 不为空则添加到部门岗位ids列表中
                departmentPositions.add(departmentPosition);
            }
        }
        // 根据当前登录用户的部门岗位关联列表查询该部门下该岗位的资源（菜单）编号列表
        for (Long departmentPosition : departmentPositions) {
            LambdaQueryWrapper<SysDeptPositionResource> sysDeptPositionResourceLambdaQueryWrapper = new LambdaQueryWrapper<>();
            sysDeptPositionResourceLambdaQueryWrapper.eq(SysDeptPositionResource::getDepartmentPosition, departmentPosition);
            sysDeptPositionResources = sysDeptPositionResourceService.selectDeptPositionResource(sysDeptPositionResourceLambdaQueryWrapper);
        }
        for (SysDeptPositionResource sysDeptPositionResource : sysDeptPositionResources) {
            LambdaQueryWrapper<SysApiPerm> sysApiPermLambdaQueryWrapper = new LambdaQueryWrapper<>();
            sysApiPermLambdaQueryWrapper.eq(SysApiPerm::getResourceId, sysDeptPositionResource.getResourceId());
            List<SysApiPerm> sysApiPerms = sysApiPermService.list(sysApiPermLambdaQueryWrapper);
            if (!sysApiPerms.isEmpty()) {
                sysApiPerms.forEach(apiPerm -> authApi.add(apiPerm.getScopePath()));
            }
        }
        List<SysApiPerm> sysApiPerms = sysApiPermService.list(new LambdaQueryWrapper<SysApiPerm>().eq(SysApiPerm::getSysFlag, 1));
        for (SysApiPerm sysApiPerm : sysApiPerms) {
            authApi.add(sysApiPerm.getScopePath());
        }
        // 2.删除原有基础接口权限缓存，并将登录成功后完整的存储至Redis中，用以网关网关进行接口鉴权
        redisService.deleteObject(userName+"@auth");
        redisService.setCacheObject(userName+"@auth",authApi,expireTime, timeUnit);
        // 3.查询当前登录用户所选择的部门下的某岗位的菜单列表
        for (SysDeptPositionResource sysDeptPositionResource : sysDeptPositionResources) {
            LambdaQueryWrapper<SysResource> sysResourceLambdaQueryWrapper = new LambdaQueryWrapper<>();
            sysResourceLambdaQueryWrapper.eq(SysResource::getId, sysDeptPositionResource.getResourceId());
            sysResourceLambdaQueryWrapper.eq(SysResource::getDelFlag, "0");
            SysResource sysResource = sysResourceService.getOne(sysResourceLambdaQueryWrapper);
            if (sysResource != null){
                sysResources.add(sysResource);
            }
        }
        // 4.菜单路由列表构建为菜单树形结构并返回
        // 使用构造方法转换为 List
        List<SysResource> menuTreeList = new ArrayList<>(sysResources);
        // 构建菜单树形结构
        List<SysResourceListTree> menuTree = ResourceTreeBuilder.buildResourceTree(menuTreeList,null);
        if (menuTree.isEmpty()){
            return R.fail("该用户所选择部门下的岗位暂未分配资源，登录失败！");
        }
        ObjectMapper objectMapper = JsonUtils.createObjectMapper();
        String writeValueAsString = objectMapper.writeValueAsString(menuTree);
        redisService.setCacheObject(userName+"@resource",writeValueAsString,expireTime,timeUnit);
        return R.success("登录成功！");
    }

    /** 登录后获取资源树
     * @return 资源树
     */
    @GetMapping("/resource")
    public R<List<SysResourceListTree>> getSysResource() throws JsonProcessingException {
        SysUser sysUser = sysUserService.getById(AuthUtil.getUserId());
        String cacheObject = redisService.getCacheObject(sysUser.getUserName() + "@resource");
        ObjectMapper objectMapper = JsonUtils.createObjectMapper();
        List<SysResourceListTree> sysResourceListTrees = objectMapper.readValue(cacheObject, new TypeReference<List<SysResourceListTree>>() {
        });
        return R.data(sysResourceListTrees);
    }

}
